package com.fishery.authority.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fishery.authority.client.BaseClient;
import com.fishery.authority.entity.*;
import com.fishery.authority.entity.vo.InvitationVo;
import com.fishery.authority.entity.vo.UserLoginPassword;
import com.fishery.authority.entity.vo.UserLoginVo;
import com.fishery.authority.entity.vo.UserVo;
import com.fishery.authority.mapper.FunctionMapper;
import com.fishery.authority.mapper.RoleMapper;
import com.fishery.authority.mapper.UserMapper;
import com.fishery.authority.security.MobileAuthenticationToken;
import com.fishery.authority.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fishery.authority.utils.SecurityContextUtil;
import com.fishery.entity.GlobalException;
import com.fishery.entity.Result;
import com.fishery.entity.StatusCode;
import com.fishery.util.MD5;
import com.fishery.util.TokenManager;
import net.bytebuddy.asm.Advice;
import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author hy
 * @since 2021-01-13
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Value(value = "${user.default.avatar}")
    private String DefaultAvatar;

    @Value("${user.ttl}")
    private int ttl;

    @Value("${user.passwordErrors}")
    private int passwordErrors;

    @Value("${invitation.cool-down}")
    private int invitationCoolDown;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private TokenManager tokenManager;

    @Autowired
    private FunctionService functionService;

    @Autowired
    private FunctionRoleService functionRoleService;

    @Autowired
    private BaseRoleFunctionService baseRoleFunctionService;

    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private UserService userService;

    @Autowired
    private FunctionMapper functionMapper;

    @Autowired
    private BaseClient baseClient;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RoleMapper roleMapper;

//    @Autowired
//    private BCryptPasswordEncoder encoder;

    /**
     * 注册
     *
     * @param userVo
     */
    @Override
    public Result register(UserVo userVo) {
        userVo.setPassword(MD5.encrypt(userVo.getPassword()));
        String phone = userVo.getPhone();
        String password = userVo.getPassword();
        Integer code = userVo.getCode();
        if(phone == null || password == null || code == null) {
             return Result.error("注册失败，请输入带*的选项。");
        }
        Object o = redisTemplate.opsForValue().get(phone);
        if(!code.equals(o)) {
            return Result.error("注册失败，验证码错误。");
        }
        User userLogin = userMapper.selectByPhone(userVo.getPhone());
        if (userLogin != null) {
            return Result.error("注册失败，该手机号已被使用。");
        }
        User user = new User();
        user.setAvatar(DefaultAvatar);
        user.setPassword(password);
        user.setPhone(phone);
        user.setTheme("metarial-dark");
        int insert = baseMapper.insert(user);
        if(insert != 1) {
            return Result.error("注册失败。");
        }
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId("1356853657858");
        userRoleService.save(userRole);
        return Result.success("注册成功");
    }

    /**
     * 通过账号密码登陆
     *
     * @param user
     * @return
     */
    @Override
    public User loginByPassword(UserLoginPassword user) {
        UserDetailsImpl userDetailsImpl = null;
        // 用户所拥有所有权限的集合（用到set集合的目的，是为了去掉重复的权限）
        // 通过用户登陆的手机号，从数据库查出对应用户名的用户
        User userLogin = userMapper.selectByPhone(user.getPhone());
        if (!(userLogin.getPassword()).equals(MD5.encrypt(user.getPassword()))) {
            // 密码匹配不成功，即密码错误错误
            // 通过'手机号_passwordErrors'，从redis中取出该用户密码已经错误的次数
            Object num = redisTemplate.opsForValue().get(userLogin.getPhone() + "_passwordErrors");
            // 如果是第一次错误，此时redis中还没有相应的'key-value'
            if (num == null) {
                // 第一次错误，redis中还没有相应的key-value，插入值为1
                redisTemplate.opsForValue().set(userLogin.getPhone() + "_passwordErrors", 1, ttl, TimeUnit.MINUTES);
            } else {
                // 不是第一次，直接把value值+1，再放入到redis中
                redisTemplate.opsForValue().set(userLogin.getPhone() + "_passwordErrors", (int) num + 1, ttl, TimeUnit.MINUTES);
                // 超出最大错误次数，直接抛出异常，并禁止用户继续操作
                if ((int) num > passwordErrors) {
//                    throw new GlobalException(StatusCode.LOGINERROR, "密码错误次数过多，请" + ttl + "分钟后重试");
                    throw new GlobalException(new Result(false, StatusCode.LOGINERROR, "密码错误次数过多，请" + ttl + "分钟后重试", null));
                }
            }
        }
        Set<GrantedAuthority> authoritySet = findFunctionMethod(userLogin);
        tokenManager.createToken(userLogin.getId(),
                userLogin.getUsername(),
                userLogin.getBaseIdentity(),
                userLogin.getBaseId(),
                authoritySet);
        // security的认证判断是通过authenticationManager去判断构造的UsernamePasswordToken
        // 然后生成验证通过后Authentication，将这个Authentication放入SecurityContextHolder中即可实现认证。
        // 所以在这里直接注入authenticationManager
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
//                new UsernamePasswordAuthenticationToken(userLogin.getId(), user.getPassword(), authorities);
                new UsernamePasswordAuthenticationToken(userLogin.getId(), user.getPassword(), authoritySet);
        Authentication authentication = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
        // 将认证放入安全上下文中
        SecurityContextUtil.setAuthentication(authentication);
        // 此时的UserDetails实例不带有权限信息
        userDetailsImpl = (UserDetailsImpl) authentication.getPrincipal();
        // 将权限信息设置到UserDetails实例中
        userDetailsImpl.setAuthorities(usernamePasswordAuthenticationToken.getAuthorities());
        // 这个对象返回给controller去生成jwt
        return userDetailsImpl;
    }

    /**
     * 通过验证码登陆
     *
     * @param userLoginVo
     * @return
     */
    @Override
    public User loginByVerification(UserLoginVo userLoginVo) {
        UserDetailsImpl userDetailsImpl = null;
        // 通过用户登陆的手机号，从数据库查出对应用户名的用户
        User userLogin = userMapper.selectByPhone(userLoginVo.getPhone());
        if((userLoginVo.getCode()).equals(redisTemplate.opsForValue().get("{" + userLoginVo.getPhone() + "}"))) {
            // 验证码匹配不成功，即验证码错误
            // 通过'手机号_passwordErrors'，从redis中取出该用户密码已经错误的次数
            Object num = redisTemplate.opsForValue().get(userLogin.getPhone() + "_LoginVerificationErrors");
            // 如果是第一次错误，此时redis中还没有相应的'key-value'
            if (num == null) {
                // 第一次错误，redis中还没有相应的key-value，插入值为1
                redisTemplate.opsForValue().set(userLogin.getPhone() + "_LoginVerificationErrors", 1, ttl, TimeUnit.MINUTES);
            } else {
                // 不是第一次，直接把value值+1，再放入到redis中
                redisTemplate.opsForValue().set(userLogin.getPhone() + "_LoginVerificationErrors", (int) num + 1, ttl, TimeUnit.MINUTES);
                // 超出最大错误次数，直接抛出异常，并禁止用户继续操作
                if ((int) num > passwordErrors) {
                    throw new GlobalException(new Result(false, StatusCode.LOGINERROR, "输入验证码错误次数过多，请" + ttl + "分钟后重试", null));
                }
            }
        }
        Set<GrantedAuthority> authoritySet = findFunctionMethod(userLogin);
        // security的认证判断是通过authenticationManager去判断构造的UsernamePasswordToken
        // 然后生成验证通过后Authentication，将这个Authentication放入SecurityContextHolder中即可实现认证。
        // 所以在这里直接注入authenticationManager
        MobileAuthenticationToken mobileAuthenticationToken =
                new MobileAuthenticationToken(userLogin.getId(), authoritySet);
        Authentication authentication = authenticationManager.authenticate(mobileAuthenticationToken);
        // 将认证放入安全上下文中
        SecurityContextUtil.setAuthentication(authentication);
        // 此时的UserDetails实例不带有权限信息
        userDetailsImpl = (UserDetailsImpl) authentication.getPrincipal();
        // 将权限信息设置到UserDetails实例中
        userDetailsImpl.setAuthorities(authoritySet);
        // 这个对象返回给controller去生成jwt
        return userDetailsImpl;
    }

    /**
     * 封装查权限方法
     *
     * @param userLogin
     * @return
     */
    private Set<GrantedAuthority> findFunctionMethod(User userLogin) {
        // 用户所拥有所有权限的集合（用到set集合的目的，是为了去掉重复的权限）
        Set<GrantedAuthority> authorities = new HashSet<>();
        //如果用户baseId不为空且基地身份不为老板, 则到authority_base_role_function读取用户权限
        //如果是老板，直接给所有权限。如果用户创建基地，那么他的baseIdentity就是boss
        if(StringUtils.isEmpty(userLogin.getBaseIdentity()) && StringUtils.isEmpty(userLogin.getBaseId())) {
            authorities = null;
        } else if (userLogin.getBaseIdentity() == 2) {
//            List<Function> bossFunctions = functionService.queryAllFunction();
            List<Function> bossFunctions = functionMapper.findByRoleIdByUserId(userLogin.getId());
            for (Function function : bossFunctions) {
                authorities.add(new SimpleGrantedAuthority(function.getName()));
            }
        } else if (!StringUtils.isEmpty(userLogin.getBaseId()) && !StringUtils.isEmpty(userLogin.getBaseIdentity())) {
            //如果不是老板，到t_authority_base_role_function表根据baseId和baseIdentity查functionId，然后查到具体function插入functionList
            List<Function> functionLists = functionMapper.findByBaseIdByBaseIdentity(userLogin.getBaseId(), userLogin.getBaseIdentity());
            for(Function function : functionLists) {
                authorities.add(new SimpleGrantedAuthority(function.getName()));
            }
        } else {
            //否则就根据userId查roleId查functionId。这个我也不理解为什么要这样做，反正对虾平台是这个逻辑
            List<Function> functionLists = functionMapper.findByRoleIdByUserId(userLogin.getId());
            for(Function function : functionLists) {
                authorities.add(new SimpleGrantedAuthority(function.getName()));
            }
        }
        return authorities;
    }

    /**
     * 本方法已弃用，改为使用sql语句查
     * 通过手机号查找用户
     *
     * @param phone
     * @return
     */
    @Override
    public User findByPhone(String phone) {
        if(phone == null) {
            throw new GlobalException(StatusCode.ERROR, "手机号为空");
        }
        User user = userMapper.selectByPhone(phone);
        return user;
    }

    /**
     * 通过用户id查找用户
     *
     * @param userId
     * @return
     */
    @Override
    public User findByUserId(String userId) {
        return baseMapper.selectById(userId);
    }

    /**
     * 修改
     *
     * @param user
     */
    @Override
    @Transactional
    public void updateUser(User user) {
        User userLogin = findByUserId(user.getId());
        if (userLogin == null) {
            throw new GlobalException(new Result(false, StatusCode.ERROR, "不存在", null));
        } else {
            try {
                user.setUsername(user.getUsername() == null ? userLogin.getUsername() : user.getUsername());
                user.setEmail(user.getEmail() == null ? userLogin.getEmail() : user.getEmail());
                user.setPhone(user.getPhone() == null ? userLogin.getPhone() : user.getPhone());
//                user.setBaseId(user.getBaseId() == null ? userLogin.getBaseId() : user.getBaseId());
//                user.setBaseIdentity(user.getBaseIdentity() == null ? userLogin.getBaseIdentity() : user.getBaseIdentity());
                user.setAvatar(user.getAvatar() == null ? userLogin.getAvatar() : user.getAvatar());

                // 密码加密
//                user.setPassword(user.getPassword() == null ? userLogin.getPassword() : MD5.encrypt(user.getPassword()));
                user.setPassword(userLogin.getPassword());
                baseMapper.updateById(user);
            } catch (Exception e) {
                throw new GlobalException(new Result(false, StatusCode.ERROR, "修改失败", null));
            }
        }
    }

    @Override
    public void findPassword(User userModified, String code) {
        User user = userService.findByPhone(userModified.getPhone());
        if(user == null) {
            throw new GlobalException(new Result(false, StatusCode.ERROR, "查无此用户", null));
        }
        if(code.equals(redisTemplate.opsForValue().get(userModified.getPhone()))) {
            // 验证码匹配不成功，即验证码错误
            // 通过'手机号_ModifiedErrors'，从redis中取出该用户验证码已经错误的次数
            Object num = redisTemplate.opsForValue().get(user.getPhone() + "_ModifiedErrors");
            // 如果是第一次错误，此时redis中还没有相应的'key-value'
            if (num == null) {
                // 第一次错误，redis中还没有相应的key-value，插入值为1
                redisTemplate.opsForValue().set(user.getPhone() + "_ModifiedErrors", 1, ttl, TimeUnit.MINUTES);
            } else {
                // 不是第一次，直接把value值+1，再放入到redis中
                redisTemplate.opsForValue().set(user.getPhone() + "_ModifiedErrors", (int) num + 1, ttl, TimeUnit.MINUTES);
                // 超出最大错误次数，直接抛出异常，并禁止用户继续操作
                if ((int) num > passwordErrors) {
                    throw new GlobalException(new Result(false, StatusCode.ERROR, "输入验证码错误次数过多，请" + ttl + "分钟后重试", null));
                }
            }
        }
        // 修改用户的密码
        user.setPassword(MD5.encrypt(userModified.getPassword()));
        int result = baseMapper.updateById(user);
        if(result != 1) {
            throw new GlobalException(new Result(false, StatusCode.ERROR, "修改密码错误", null));
        }
    }

    /**
     * 申请基地管理员
     *
     * @param userId
     * @param baseId
     * @param baseIdentity
     */
    @Override
    public void applyForBaseAdmin(String userId, String baseId, int baseIdentity) {
        try {
            // 查找用户是否存在
            User user = baseMapper.selectById(userId);
            if(user == null) {
                throw new GlobalException(new Result(false, StatusCode.ERROR, "查无此账户", null));
            }
            // 可能有未处理的申请
            // 先读取，加入新的，再重新加回去
            Map<String, Map> message = (Map) redisTemplate.opsForValue().get("baseMessage");
            // redis中没有请求信息
            if (message == null) {
                message = new HashMap<>();
            }

            Map<String, String> map = new HashMap<>();
            map.put("baseId", baseId);
            map.put("baseIdentity", String.valueOf(baseIdentity));

            message.put(userId, map);

            redisTemplate.opsForValue().set("baseMessage", message);
        } catch (GlobalException e) {
            throw new GlobalException(new Result(false, StatusCode.ERROR, e.getMessage(), null));
        } catch (Exception e) {
            e.printStackTrace();
            throw new GlobalException(new Result(false, StatusCode.ERROR, "申请失败", null));
        }
    }

    /**
     * 申请基地管理员的状态
     *
     * @param userId
     * @return
     */
    @Override
    public Map<String, String> applyForStatus(String userId) {
        Map<String, String> map = null;
        Map<String, Map> message = (Map) redisTemplate.opsForValue().get("baseMessage");
        if (message != null) {
            map = message.get(userId);
        }

        return map;
    }


    /**
     * 申请新建基地
     *
     * @param userId
     * @param base
     */
    @Override
    public void applyForAddBase(String userId, Base base) {
        try {
            // 查找用户是否存在
            User user = baseMapper.selectById(userId);
            if(user == null) {
                throw new GlobalException(new Result(false, StatusCode.ERROR, "查无此用户", null));
            }
            // 可能有未处理的申请
            // 先读取，加入新的，再重新加回去
            Map<String, Base> message = (Map) redisTemplate.opsForValue().get("addBaseMessage");
            // redis中没有请求信息
            if (message == null) {
                message = new HashMap<>();
            }

            message.put(userId, base);

            redisTemplate.opsForValue().set("addBaseMessage", message);
        } catch (GlobalException e) {
            throw new GlobalException(new Result(false, StatusCode.ERROR, e.getMessage(), null));
        } catch (Exception e) {
            e.printStackTrace();
            throw new GlobalException(new Result(false, StatusCode.ERROR, "申请失败", null));
        }
    }

    /**
     * 申请新建基地的状态
     *
     * @param userId
     * @return
     */
    @Override
    public Base applyForAddBaseStatus(String userId) {
        Base base = null;
        Map<String, Base> message = (Map) redisTemplate.opsForValue().get("addBaseMessage");
        if (message != null) {
            base = message.get(userId);
        }

        return base;
    }

    /**
     * 查询基地信息
     *
     * @param userId 用户id
     * @return 返回基地id和改用户在基地的身份
     */
    @Override
    public HashMap<String, Object> getBase(String userId) {
        try {
            HashMap<String, Object> map = new HashMap<>();
            User byId = userService.getById(userId);
            String baseId = byId.getBaseId();
            Integer baseIdentity = byId.getBaseIdentity();

            if (baseId != null && !"".equals(baseIdentity)) {
                map.put("baseId", baseId);
                map.put("baseIdentity", baseIdentity);
            } else {
                return null;
            }
            return map;
        } catch (GlobalException e) {
            e.printStackTrace();
            throw new GlobalException(new Result(false, StatusCode.ERROR, e.getMessage(), null));
        } catch (Exception e) {
            e.printStackTrace();
//            throw new GlobalException(new Result(false, StatusCode.ERROR, "获取基地信息失败", null));
            throw new GlobalException(Result.error("获取基地信息失败"));
        }
    }

    /**
     * 邀请用户进基地
     *
     * @param userId
     * @param baseId
     */
    @Override
    public void inviteUserIntoBase(String userId, String baseId) {
        // 查询用户是否存在
        User user = baseMapper.selectById(userId);
        if (user == null) {
            // 用户不存在
            throw new GlobalException(Result.error(StatusCode.ERROR, "用户不存在"));
        }
        if (!StringUtils.isEmpty(user.getBaseId())) {
            // 用户已有自己的基地
            throw new GlobalException(Result.error(StatusCode.ERROR, "该用户已有基地"));
        }

        // 保存基地对用户的邀请
        LinkedList<String> baseIdList = (LinkedList<String>) redisTemplate.opsForHash().get("InvitationMessage", userId);
        // 保存基地的邀请记录,存在三种状态等待(2)，同意(1)，拒绝(0)
        Map<String, LinkedList<String>> invitationRecord = (Map<String, LinkedList<String>>) redisTemplate.opsForHash().get("InvitationRecord", baseId);
        // 第一次邀请，redis不存在该对象
        if (invitationRecord == null) {
            invitationRecord = new HashMap<String, LinkedList<String>>();
            invitationRecord.put("0", new LinkedList<String>());
            invitationRecord.put("1", new LinkedList<String>());
            invitationRecord.put("2", new LinkedList<String>());
        }
        LinkedList<String> waitingInvitationRecord = invitationRecord.get("2");

        if (baseIdList == null) {
            // 没有基地邀请该用户
            baseIdList = new LinkedList<>();
        } else {
            // 判断是否已经被该基地邀请
            if (baseIdList.contains(baseId)) {
                // 该基地已对该用户发过邀请
                // 检测冷却时间是否已过
                Object o = redisTemplate.opsForValue().get("InvitationCool_" + baseId + userId);
                if (o != null) {
                    // 冷却时间还未过
                    throw new GlobalException(Result.error(StatusCode.DUPLICATE, "邀请过于繁忙，请明天再来"));
                }
                // 冷却时间过了，InvitationMessage中对该基地的记录，删除waitingInvitationRecord的该用户发送邀请的记录
                baseIdList.remove(baseId);
                waitingInvitationRecord.remove(baseId);
            }
        }

        // 发送邀请,UserId作为redis的key，linkedList作为value（linkedList头部放入baseId）
        baseIdList.addFirst(baseId);
        redisTemplate.opsForHash().put("InvitationMessage", userId, baseIdList);
        // 基地保存邀请记录
        waitingInvitationRecord.addFirst(userId);
        redisTemplate.opsForHash().put("InvitationRecord", baseId, invitationRecord);
        // 以'InvitationCool_ baseId+userId'作为key，value值设置为1,过期时间为冷却时间
        redisTemplate.opsForValue().set("InvitationCool_" + baseId + userId, 1, invitationCoolDown, TimeUnit.SECONDS);
    }

    /**
     * 基地获取邀请用户记录
     *
     * @param baseId
     * @return
     */
    @Override
    public List<InvitationVo> getInvitationRecord(String baseId) {
        // 判断基地是否存在
        if (StringUtils.isEmpty(baseId) || baseClient.getBaseInfo(baseId).getData() == null) {
//            if (StringUtils.isEmpty(baseId)) {
            throw new GlobalException(Result.error(StatusCode.ERROR, "基地不存在"));
        }
        // 获取基地所有邀请记录
        Map<String, LinkedList<String>> invitationRecord =
                (Map<String, LinkedList<String>>) redisTemplate.opsForHash().get("InvitationRecord", baseId);
        if (invitationRecord == null) {
            // 该基地没有邀请过人
            return null;
        }
        LinkedList<InvitationVo> invitationVos = new LinkedList<>();

        // 等待记录
        LinkedList<String> waitingLinkedList = invitationRecord.get("2");
        // 同意记录
        LinkedList<String> acceptedLinkedList = invitationRecord.get("1");
        // 拒绝记录
        LinkedList<String> refusedLinkedList = invitationRecord.get("0");


        // 查库，进行组装
        if (waitingLinkedList != null && waitingLinkedList.size() != 0) {
            baseMapper.selectBatchIds(waitingLinkedList).stream().forEach(user -> {
                InvitationVo invitationVo = new InvitationVo();
                BeanUtils.copyProperties(user, invitationVo);
                invitationVo.setStatus("2");
                invitationVo.setPassword(null);
                invitationVos.add(invitationVo);
            });
        }

        if (acceptedLinkedList != null && acceptedLinkedList.size() != 0) {
            baseMapper.selectBatchIds(acceptedLinkedList).stream().forEach(user -> {
                InvitationVo invitationVo = new InvitationVo();
                BeanUtils.copyProperties(user, invitationVo);
                invitationVo.setStatus("1");
                invitationVo.setPassword(null);
                invitationVos.add(invitationVo);
            });
        }

        if (refusedLinkedList != null && refusedLinkedList.size() != 0) {
//            userDao.findAllById(refusedLinkedList).stream().forEach(user -> {
            baseMapper.selectBatchIds(refusedLinkedList).stream().forEach(user -> {
                InvitationVo invitationVo = new InvitationVo();
                BeanUtils.copyProperties(user, invitationVo);
                invitationVo.setStatus("0");
                invitationVo.setPassword(null);
                invitationVos.add(invitationVo);
            });
        }
        return invitationVos;
    }

    /**
     * 基地获取指定类型的邀请记录
     *
     * @param baseId
     * @param typeId
     * @return
     */
    @Override
    public List<User> getTypeInvitationRecord(String baseId, String typeId) {
        // 判断基地是否存在
        if (StringUtils.isEmpty(baseId) || baseClient.getBaseInfo(baseId).getData() == null) {
            throw new GlobalException(Result.error(StatusCode.ERROR, "基地不存在"));
        }
        // 获取基地所有邀请记录
        Map<String, LinkedList<String>> invitationRecord = (Map<String, LinkedList<String>>) redisTemplate.opsForHash().get("InvitationRecord", baseId);
        if (invitationRecord == null
                || invitationRecord.get(typeId) == null
                || invitationRecord.get(typeId).size() == 0) {
            // 该基地没有邀请过人或没有这种类型的记录
            return null;
        }
        // 获取指定类型的邀请记录，进行查库封装数据
        return baseMapper.selectBatchIds(invitationRecord.get(typeId));
    }

    /**
     * 用户查询目前被哪些基地邀请
     *
     * @param userId
     * @return
     */
    @Override
    public List<Map<String, String>> findAllInvitation(String userId) {
        LinkedList<String> baseIdList = (LinkedList<String>) redisTemplate.opsForHash().get("InvitationMessage", userId);
        // 判断baseIdList是否为空
        if (baseIdList == null) {
            // baseIdList为空，表示没有基地邀请该用户
            return null;
        }
        // baseIdList不为空
        // 创建一个存储base的List集合
        List<Map<String, String>> baseInfoList = new ArrayList<Map<String, String>>();
        // 通过baseIdList存储的baseId调用远程服务来获取每个base
        for (String baseId : baseIdList) {
            Map<String, String> baseInfo = (Map<String, String>) baseClient.getBaseInfo(baseId).getData();
            if (baseInfo != null) {
                baseInfoList.add(baseInfo);
            }
        }
        return baseInfoList;
    }

    /**
     * 用户选择选择同意（拒绝）进入基地
     *
     * @param userId
     * @param baseId
     * @param selection
     */
    @Transactional
    @Override
    public void executeSelection(String userId, String baseId, String selection) {
        // 判断该baseId的基地是否存在
        if (baseClient.getBaseInfo(baseId).getData() == null) {
            //基地不存在
            throw new GlobalException(Result.error(StatusCode.ERROR, "传入的baseId有误"));
        }
        // 获取通过redis获取邀请该用户的基地ID
        LinkedList<String> baseIdList = (LinkedList<String>) redisTemplate.opsForHash().get("InvitationMessage", userId);
        if (baseIdList == null) {
            // 主要是防止有基地的用户直接非法操作进到该接口,message可随便填写
            throw new GlobalException(Result.error(StatusCode.ERROR, "邀请已过期"));
        }
        // 判断是否该baseId基地有邀请该用户
        if (!baseIdList.contains(baseId)) {
            // 该baseId基地没有邀请该用户
            throw new GlobalException(Result.error(StatusCode.ERROR, "传入的baseId有误"));
        }

        // 判断用户选择了哪一项
        if (selection.equals("1")) {
            // 选择了同意
            for (String baseIdStr : baseIdList) {
                // 删除所有基地的对该用户的等待记录
                Map<String, LinkedList<String>> invitationRecord = (Map<String, LinkedList<String>>) redisTemplate.opsForHash().get("InvitationRecord", baseIdStr);
                invitationRecord.get("2").remove(userId);
                // 删除所有基地对该该用户邀请对冷却时间限制
                redisTemplate.delete("InvitationCool_" + baseIdStr + userId);
                // 判断当前遍历到的基地是否为用户同意进入的基地
                if (baseId.equals(baseIdStr)) {
                    // 该基地为用户同意进入的基地
                    // 该基地的同意日志进行记录
                    invitationRecord.get("1").addFirst(userId);
                } else {
                    // 该基地不是用户同意进入的基地
                    // 该基地的拒绝日志进行记录
                    invitationRecord.get("0").addFirst(userId);
                }
                redisTemplate.opsForHash().put("InvitationRecord", baseIdStr, invitationRecord);
            }
            // 删除该用户的所有基地邀请
            redisTemplate.opsForHash().delete("InvitationMessage", userId);
            // 修改用户的信息（添加上baseId字段和baseIdentity字段）,初始化身份是员工
            userMapper.setBase(baseId, 4, userId);
        } else {
            // 选择了拒绝
            // 对基地邀请人记录进行修改，等待记录中删除该用户，拒绝记录增加该用户
            Map<String, LinkedList<String>> invitationRecord = (Map<String, LinkedList<String>>) redisTemplate.opsForHash().get("InvitationRecord", baseId);
            invitationRecord.get("2").remove(userId);
            invitationRecord.get("0").addFirst(userId);
            redisTemplate.opsForHash().put("InvitationRecord", baseId, invitationRecord);
            // 删除该用户该基地的邀请
            baseIdList.remove(baseId);
            redisTemplate.opsForHash().put("InvitationMessage", userId, baseIdList);
        }
    }

    /**
     * 基地清空所有邀请记录
     *
     * @param baseId
     */
    @Override
    public void deleteInvitationRecordByBaseId(String baseId) {
        // 查询基地是否存在
        if (baseClient.getBaseInfo(baseId).getData() == null) {
            throw new GlobalException(Result.error(StatusCode.ERROR, "删除失败"));
        }
        // 从redis中获取基地的邀请日志
        Map<String, LinkedList<String>> invitationRecord = (Map<String, LinkedList<String>>) redisTemplate.opsForHash().get("InvitationRecord", baseId);
        if (invitationRecord == null) {
            throw new GlobalException(Result.error(StatusCode.ERROR, "删除失败"));
        }
        invitationRecord.put("0", new LinkedList<String>());
        invitationRecord.put("1", new LinkedList<String>());
        invitationRecord.put("2", new LinkedList<String>());
        redisTemplate.opsForHash().put("InvitationRecord", baseId, invitationRecord);
    }

    /**
     * 基地清空指定类型的邀请记录
     *
     * @param baseId
     */
    @Override
    public void deleteTypeInvitationRecord(String baseId, String typeId) {
        // 查询基地是否存在
        if (baseClient.getBaseInfo(baseId).getData() == null) {
            throw new GlobalException(Result.error(StatusCode.ERROR, "删除失败"));
        }
        // 从redis中获取基地的邀请日志
        Map<String, LinkedList<String>> invitationRecord = (Map<String, LinkedList<String>>) redisTemplate.opsForHash().get("InvitationRecord", baseId);
        if (invitationRecord == null || invitationRecord.get(typeId) == null || invitationRecord.get(typeId).size() == 0) {
            throw new GlobalException(Result.error(StatusCode.ERROR, "删除失败"));
        }
        invitationRecord.put(typeId, new LinkedList<String>());
        redisTemplate.opsForHash().put("InvitationRecord", baseId, invitationRecord);
    }

    /**
     * 基地清除某一条邀请记录
     *
     * @param userId
     * @param baseId
     */
    @Override
    public void deleteInvitationRecordByUserId(String userId, String baseId, String typeId) {
        Map<String, LinkedList<String>> invitationRecord = (Map<String, LinkedList<String>>) redisTemplate.opsForHash().get("InvitationRecord", baseId);
        if (invitationRecord == null) {
            throw new GlobalException(Result.error(StatusCode.ERROR, "删除失败"));
        }
        LinkedList<String> userIdList = invitationRecord.get(typeId);
        boolean flag = userIdList.remove(userId);
        if (!flag) {
            throw new GlobalException(Result.error(StatusCode.ERROR, "删除失败"));
        }
        invitationRecord.put(typeId, userIdList);
        redisTemplate.opsForHash().put("InvitationRecord", baseId, invitationRecord);
    }

    /**
     * 用户清空所有待确认记录
     *
     * @param userId
     */
    @Override
    public void deleteAllInvitation(String userId) {
        // 查询用户是否已经有基地了，如果有基地了，那一定没有记录
        if (baseClient.getBaseInfo(userId).getData() != null) {
            throw new GlobalException(Result.error(StatusCode.ERROR, "删除失败"));
        }
        // 获取用户所有待确认记录
        LinkedList<String> baseIdList = (LinkedList<String>) redisTemplate.opsForHash().get("InvitationMessage", userId);
        for (String str : baseIdList) {
            Map<String, LinkedList<String>> invitationRecordMap = (Map<String, LinkedList<String>>) redisTemplate.opsForHash().get("InvitationRecord", str);
            invitationRecordMap.get("2").remove(userId);
            invitationRecordMap.get("0").add(userId);
            redisTemplate.opsForHash().put("InvitationRecord", str, invitationRecordMap);
        }
        redisTemplate.opsForHash().delete("InvitationMessage", userId);
    }

    /**
     * 用户删除指定基地的邀请
     *
     * @param userId
     * @param baseId
     */
    @Override
    public void deleteInvitationByBaseId(String userId, String baseId) {
        executeSelection(userId, baseId, "0");
    }

    /**
     * 根据老板用户Id获取基地用户
     *
     * @param userId
     * @return
     */
    @Override
    public List<User> getUsersByUserId(String userId) {
        try {
            User baseUser = findByUserId(userId);
//            ArrayList<User> users = userMapper.getUsersByBaseId(baseUser.getBaseId());
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.eq("baseId", baseUser.getBaseId());
            List<User> users = baseMapper.selectList(wrapper);
            for (User user : users) {
                user.setPassword(null);
            }
            return users;
        } catch (GlobalException e) {
            e.printStackTrace();
            throw new GlobalException(new Result(false, StatusCode.ERROR, e.getMessage(), null));
        } catch (Exception e) {
            e.printStackTrace();
            throw new GlobalException(new Result(false, StatusCode.ERROR, "获取用户信息失败", null));
        }
    }

    /**
     * 修改雇员用户的基地身份
     *
     * @param userId
     * @param baseIdentity
     * @return
     */
    @Transactional
    @Override
    public void updateBaseIdentityOfUser(String userId, Integer baseIdentity) {
        User boss = findByUserId(SecurityContextUtil.getUserDetails().getId());
        User employee = findByUserId(userId);
        if (employee == null) {
            throw new GlobalException(new Result(false, StatusCode.ERROR, "所修改的用户不存在", null));
        } else if (boss.getBaseIdentity() != 2 ||
                employee.getBaseIdentity() == 2 ||
                boss.getBaseId() == null ||
                !boss.getBaseId().equals(employee.getBaseId())) {
            throw new GlobalException(new Result(false, StatusCode.ERROR, "修改失败", null));
        }
        userMapper.setBase(boss.getBaseId(), baseIdentity, userId);
    }

    /**
     * 分页查询基地用户信息（不包含当前用户的数据）
     *
     * @param userId
     * @param baseId
     * @return
     */
    @Override
    public List<User> getBaseMemberList(String userId, String baseId) {
        List<User> userList = userMapper.findOthersByBaseIdAndUserId(baseId, userId);
        userList.stream().forEach(user -> user.setPassword(null));
        return userList;
    }

    /**
     * 解雇员工
     *
     * @param userId       要解雇的员工ID
     * @param baseId       当前基地ID
     * @param baseIdentity 当前操作删的身份
     */
    @Transactional
    @Override
    public void sackEmployeeByUserIdAndBaseId(String userId, String baseId, Integer baseIdentity) {
//        User user = userMapper.findByUserIdAndBaseId(userId, baseId);
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("id", userId);
        wrapper.eq("base_id", baseId);
        User user = baseMapper.selectOne(wrapper);
        if (user == null || user.getBaseIdentity() <= baseIdentity) {
            throw new GlobalException(Result.error(StatusCode.ERROR, "解雇失败"));
        }
        user.setBaseId(null);
        user.setBaseIdentity(null);
        QueryWrapper wrapper1 = new QueryWrapper();
        baseMapper.update(user, wrapper1);
//        userDao.setBaseNullByUserId(userId);
    }











    /**
     * 查询全部普通管理员列表
     *
     * @return
     */
    @Override
    public List<User> findAllAdmin() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("is_admin", 1);
        QueryWrapper<User> wrapper2 = new QueryWrapper<>();
        wrapper2.eq("is_admin", 1);
        List<User> users = baseMapper.selectList(wrapper);
        List<User> users2 = baseMapper.selectList(wrapper2);
        users.addAll(users2);
        return users;
    }

    /**
     * 根据ID查询管理员
     *
     * @param userId
     * @return
     */
    @Override
    public User findAdminByUserId(String userId) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("is_admin", 1);
        wrapper.eq("id", userId);
        QueryWrapper<User> wrapper2 = new QueryWrapper<>();
        wrapper2.eq("is_admin", 1);
        wrapper.eq("id", userId);
        User user1 = baseMapper.selectOne(wrapper);
        User user2 = baseMapper.selectOne(wrapper2);
        // 若为空就抛出错误
        if (user1 != null && !"".equals(user1)) {
            return user1;
        } else if (user2 != null && !"".equals(user2)) {
            return user2;
        } else {
            throw new GlobalException(Result.error("用户不存在"));
        }
    }

    /**
     * 更新管理员角色
     *
     * @param userId
     * @param RoleIdList
     */
    @Transactional
    @Override
    public void UpdateRoleOfAdmin(String userId, Map RoleIdList) {
        try {
            // 查询用户
            User user = findAdminByUserId(userId);
            if (user == null) {
                throw new RuntimeException("管理员不存在");
            }

            // 删除用户的所有角色
            userMapper.deleteALLById(userId);

            List<Object> roleList = (List<Object>) RoleIdList.get("roleIdList");
            for (Object roleId : roleList) {
                // 查询角色
                // id不为空但查询结果为空
                Role role = roleMapper.selectById((String) roleId);
                if (roleId != null) {
                    throw new RuntimeException(roleId + "角色不存在");
                }
                // 添加权限
                userMapper.addRoleToUser(userId, (String) roleId);
            }
        } catch (Exception e) {
            throw new GlobalException(Result.error("给管理员添加角色失败,"));
        }
    }

    /**
     * 更新基地管理员
     *
     * @param userId
     * @param baseId
     * @param baseIdentity
     */
    @Transactional
    @Override
    public void updateBaseAdmin(String userId, String baseId, Integer baseIdentity) {
        try {
            User user = findByUserId(userId);
            user.setBaseId(baseId);
            user.setBaseIdentity(baseIdentity);
            updateUser(user);
        } catch (GlobalException e) {
            throw new GlobalException(Result.error(e.getMessage()));
        } catch (Exception e) {
            throw new GlobalException(Result.error("授权失败"));
        }
    }

    /**
     * 删除基地的时候修改用户的基地信息为空
     *
     * @param baseId
     * @return
     */
    @Transactional
    @Override
    public Result delBase(String baseId) {
        userMapper.setBaseNull(baseId);
        return baseClient.delBase(baseId);
    }

    /**
     * 根据基地Id获取用户
     *
     * @param BaseId
     * @return
     */
    @Override
    public List<User> getUserByBaseId(String BaseId) {
        try {
            List<User> users = userMapper.getUsersByBaseId(BaseId);
            for (User user : users) {
                user.setPassword(null);
            }
            return users;
        } catch (GlobalException e) {
            e.printStackTrace();
            throw new GlobalException(new Result(false, StatusCode.ERROR, e.getMessage(), null));
        } catch (Exception e) {
            e.printStackTrace();
            throw new GlobalException(new Result(false, StatusCode.ERROR, "获取用户信息失败", null));
        }
    }

    @Override
    public List<User> findBaseMemberByBaseId(String baseId) {
        if(StringUtils.isEmpty(baseId)) {
            throw new GlobalException(Result.error("基地为空"));
        }
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("base_id", baseId);
        return baseMapper.selectList(wrapper);
    }

}
